package cn.lg.soar.general.s3;

import cn.lg.soar.common.util.FileTypeUtils;
import cn.lg.soar.common.util.FileUtil;
import cn.lg.soar.common.util.StreamUtil;
import cn.lg.soar.general.api.enums.FileStorageTypeEnum;
import cn.lg.soar.general.api.enums.ThumbnailSizeEnum;
import cn.lg.soar.general.entity.FileStorage;
import com.amazonaws.services.s3.model.AmazonS3Exception;
import com.amazonaws.services.s3.model.Bucket;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import net.coobird.thumbnailator.Thumbnails;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * @author luguoxiang 469599794@qq.com
 * @Date: 2024/3/1 17:25
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public interface FileTemplate {

    Logger LOGGER = LoggerFactory.getLogger(FileTemplate.class);

    /**
     * 创建bucket
     * @param bucketName bucket名称
     */
    void createBucket(String bucketName);

    /**
     * 通过bucket名称删除bucket
     * @param bucketName bucket名称
     */
    void removeBucket(String bucketName);

    /**
     * 获取所有的bucket
     * @return
     */
    List<Bucket> listBuckets();

    /**
     * 上传文件
     * @param bucketName bucket名称
     * @param filename 文件名称
     * @param stream 文件流
     * @throws Exception
     */
    void upload(String bucketName, String filename, InputStream stream);

    /**
     * 上传文件
     * @param bucketName bucket名称
     * @param filename 文件名称
     * @param file 文件
     */
    default void upload(String bucketName, String filename, File file) {
        try {
            upload(bucketName, filename, Files.newInputStream(file.toPath()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 获取文件
     * @param bucketName bucket名称
     * @param filename 文件名称
     * @return S3Object
     */
    S3Object getObject(String bucketName, String filename);

    default S3Object getObject(String bucketName, String filename, ThumbnailSizeEnum size) {
        if (size == null || !FileTypeUtils.isImage(filename)) {
            return getObject(bucketName, filename);
        }

        int i = filename.lastIndexOf(".");
        String tfn = filename.substring(0, i + 1) + size + filename.substring(i);
        try {
            return getObject(bucketName, tfn);
        } catch (AmazonS3Exception ignored) {

        }
        S3Object s3Object = getObject(bucketName, filename);
        try {
            // 读取图片
            BufferedImage image = ImageIO.read(s3Object.getObjectContent());
            int width = image.getWidth();
            int height = image.getHeight();
            // 压缩处理
            Thumbnails.Builder<BufferedImage> builder;
            switch (size) {
                case s:
                    if (width > (80 * 1.2) || height > (80 * 1.2)) {
                        builder = Thumbnails.of(image).size(80, 80);
                        break;
                    }
                    return getObject(bucketName, filename);
                case m:
                    if (width > (320 * 1.2) || height > (320 * 1.2)) {
                        builder = Thumbnails.of(image).size(320, 320);
                        break;
                    }
                    return getObject(bucketName, filename);
                default:
                    if (width > (1280 * 1.2) || height > (1280 * 1.2)) {
                        builder = Thumbnails.of(image).size(1280, 1280);
                        break;
                    }
                    return getObject(bucketName, filename);
            }
            String suffix = FileUtil.getSuffix(filename);
            // 设置输出格式
            builder.outputQuality(0.7)
                    .outputFormat(suffix);
            // 保存压缩图片
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            builder.toOutputStream(byteArrayOutputStream);
            asyncUpload(bucketName, tfn, StreamUtil.byteArrayOutputStreamToInputStream(byteArrayOutputStream));
            s3Object.setObjectContent(StreamUtil.byteArrayOutputStreamToInputStream(byteArrayOutputStream));
            byteArrayOutputStream.close();
            return s3Object;
        } catch (IOException | RuntimeException e2) {
            LOGGER.error("图片压缩异常", e2);
        }
        return getObject(bucketName, filename);
    }

    /**
     * 异步上传
     * @param bucketName
     * @param filename
     * @param stream
     * @return
     */
    default CompletableFuture<Void> asyncUpload(String bucketName, String filename, InputStream stream) {
        return CompletableFuture.runAsync(() -> {
            upload(bucketName, filename, stream);
        });
    }

    /**
     * 根据文件前置查询文件
     * @param bucketName bucket名称
     * @param prefix 前缀
     * @param recursive 是否递归查询
     * @return S3ObjectSummary 列表
     */
    List<S3ObjectSummary> listObjects(String bucketName, String prefix, boolean recursive);

    /**
     * 获取对象的访问路径
     * @param bucketName
     * @param filename
     * @param expires
     * @return
     */
    String getUrl(String bucketName, String filename, Integer expires);

    /**
     * 获取对象的访问路径
     * @param bucketName
     * @param filename
     * @param expires
     * @return
     */
    String getUrl(String bucketName, String filename);

    /**
     * 通过bucketName和filename删除对象
     * @param bucketName
     * @param filename
     * @throws Exception
     */
    void removeFile(String bucketName, String filename);

    /**
     * 判断文件是否存在
     * @param bucketName bucket名称
     * @param filename 文件名称
     * @return
     */
    boolean isExist(String bucketName, String filename);

    /**
     * 获取配置版本
     * @return
     */
    int getConfigVersion();

    /**
     * 测试是否可用
     * @return
     */
    void test();

    /**
     * 关闭连接
     */
    void disconnect();

    /**
     * 创建实例
     * @param fileStorage
     * @return
     */
    static FileTemplate create(FileStorage fileStorage) {
        FileStorageTypeEnum type = fileStorage.getType();
        if (FileStorageTypeEnum.AMAZON_S3.equals(type)) {
            return new AmazonS3FileTemplateImpl(fileStorage);
        }
        if (FileStorageTypeEnum.FTP.equals(type)) {
            return new FtpFileTemplateImpl(fileStorage);
        }
        return new LocalFileTemplateImpl(fileStorage);
    }

}